package scalab.core

import scala.collection.immutable.{Set, HashSet}

trait Buildable{

	import component.{Component, Universe, SinkComponent, ExecutableComponent}
	import scalab.core.gates.{Input, Output}
	import event.{Listener, UpdateStarted, UpdateFinished}
	
  /**
  * Indicates whether this <code>Buildable</code>
  * object is up-to-date.
  */
  //def upToDate: Boolean = upToDate(Nil)._1

	/**
	* Indicates whether this <code>Buildable</code>
	*	Object is up-to-date.
	*	@param fresh a list of <code>Buildable</code>
	*		objects that are guaranteed to be up-to-date.
	*		This method is used for optimization.
	*/
	private[core] def upToDate(
		products: Set[Resource],
		visited: Set[Component], 
		cycles: Set[(Output, Input)], 
		fresh: Set[ExecutableComponent]): (
			Boolean, 
			Set[Component], 
			Set[(Output, Input)], 
			Set[ExecutableComponent]
		)

	//def locallyUpToDate(products: Set[Resource]): Boolean

  /**
  * Updates this <code>Buildable</code> object when possible.
  */
  //private[core] def update(fresh: Set[Buildable]): Boolean = update(fresh)._1
	private[core] def update(
		visited: Set[Component], 
		cycles: Set[(Output, Input)], 
		fresh: Set[ExecutableComponent]): (
			Boolean, 
			Set[Component], 
			Set[(Output, Input)], 
			Set[ExecutableComponent]
		)

	//handle cycles... => not need for BlackboxIn anymore...
	//private[core] def validate(validated: Set[Buildable]): Pair[Boolean, Set[Buildable]]

	private[core] def validate(
		visited: Set[Component], 
		cycles: Set[(Output, Input)], 
		fresh: Set[SinkComponent]): (
			Boolean, 
			Set[Component], 
			Set[(Output, Input)], 
			Set[SinkComponent]
		)

	private var updateStartedListeners: List[Listener[UpdateStarted]] = Nil
	private var updateFinishedListeners: List[Listener[UpdateFinished]] = Nil
	def listenUpdateStarted(listener: UpdateStarted => Unit){
			updateStartedListeners = Listener[UpdateStarted](listener) :: updateStartedListeners
	}
	def listenUpdateFinished(listener: UpdateFinished => Unit){
			updateFinishedListeners = Listener[UpdateFinished](listener) :: updateFinishedListeners
	}
	private[core] def fireUpdateStarted{
		val event = UpdateStarted(this)
		updateStartedListeners foreach {l => l(event)}
	}
	private[core] def fireUpdateFinished(succeeded: Boolean){
		val event = UpdateFinished(this, succeeded)
		updateFinishedListeners foreach {l => l(event)}
	}

	private[core] def reverseListeners{
		updateStartedListeners = updateStartedListeners.reverse
		updateFinishedListeners = updateFinishedListeners.reverse
	}

	Buildable.allBuildables = Buildable.allBuildables + this
  //protected[core] def cycleFreeUpdate: Boolean
}

object Buildable{
	private var allBuildables: Set[Buildable] = HashSet.empty[Buildable]
	def getAll: Set[Buildable] = allBuildables
}
